/**
 * Wihidum - Efficient Broker Hierarchy for Publish Subscribe Middleware
 *
 * License      :   Apache License 2.0
 * Home Page    :   http://code.google.com/p/wihidum/
 * Mailing List :   wihidum@googlegroups.com
 */

package lk.mrt.cse.wihidum.admin.client;

import lk.mrt.cse.wihidum.storage.Broker;
import lk.mrt.cse.wihidum.storage.MessageTrace;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

/**
 * The UI of subscriber service client
 */
public class UserInterface
        extends JFrame
{
    private Client client = new Client(this);
    private ArrayList<Broker> brokerList;
    private ArrayList<MessageTrace> messageTraceList;

    private JTextField adminAddress = new JTextField("http://localhost:8080/axis2/services/Wihidum-Admin-Service");
    private JTextField insertBrokerAddress = new JTextField();
    private JTextField removeBrokerAddress = new JTextField();
    private JComboBox topologies = new JComboBox();
    private JButton insertCommand = new JButton("Insert");
    private JButton removeCommand = new JButton("Remove");
    private JButton changeCommand = new JButton("Change");
    private JButton traceCommand = new JButton("Refresh");
    private JButton mapCommand = new JButton("Refresh");
    private JLabel informationBar = new JLabel("  ");
    private JScrollPane messageScrollPane = new JScrollPane();
    private JScrollPane traceScrollPane = new JScrollPane();
    private JScrollPane mapScrollPane = new JScrollPane();
    private JScrollPane unitsScrollPane = new JScrollPane();
    private JTable brokersTable = new JTable();
    private JTable brokerUnitsTable = new JTable();
    private JTable messagesTable = new JTable();
    private JTable traceTable = new JTable();
    private DefaultTableModel messagesTableModel = new DefaultTableModel()
    {
        public boolean isCellEditable(int row, int column)
        {
            return false;
        }
    };
    private DefaultTableModel traceTableModel = new DefaultTableModel()
    {
        public boolean isCellEditable(int row, int column)
        {
            return false;
        }
    };
    private DefaultTableModel brokersTableModel = new DefaultTableModel()
    {
        public boolean isCellEditable(int row, int column)
        {
            return false;
        }
    };
    private DefaultTableModel brokerUnitsTableModel = new DefaultTableModel()
    {
        public boolean isCellEditable(int row, int column)
        {
            return false;
        }
    };

    /**
     * Default constructor
     */
    public UserInterface()
    {
        initComponents();
    }

    /**
     * Add components to the UI
     */
    public void initComponents()
    {
        JPanel adminAddressPanel = new JPanel(new BorderLayout());
        adminAddressPanel.setBorder(BorderFactory.createEmptyBorder(10, 30, 30, 30));
        adminAddressPanel.add(new JLabel("Admin Address"), BorderLayout.WEST);
        adminAddressPanel.add(adminAddress, BorderLayout.EAST);

        JPanel insertPanel = new JPanel();
        insertPanel.setLayout(new BoxLayout(insertPanel, BoxLayout.X_AXIS));
        insertPanel.setBorder(BorderFactory.createEmptyBorder(155, 30, 170, 30));
        insertPanel.add(new JLabel("Broker "));
        insertPanel.add(insertBrokerAddress);
        insertPanel.add(insertCommand);

        JPanel removePanel = new JPanel();
        removePanel.setLayout(new BoxLayout(removePanel, BoxLayout.X_AXIS));
        removePanel.setBorder(BorderFactory.createEmptyBorder(155, 30, 170, 30));
        removePanel.add(new JLabel("Broker "));
        removePanel.add(removeBrokerAddress);
        removePanel.add(removeCommand);

        JPanel changePanel = new JPanel();
        changePanel.setLayout(new BoxLayout(changePanel, BoxLayout.X_AXIS));
        changePanel.setBorder(BorderFactory.createEmptyBorder(155, 30, 170, 30));
        topologies.addItem("Tree");
        topologies.addItem("Cluster");
        changePanel.add(new JLabel("Topology "));
        changePanel.add(topologies);
        changePanel.add(changeCommand);

        messagesTableModel.addColumn("Type");
        messagesTableModel.addColumn("Start");
        traceTableModel.addColumn("ID");
        traceTableModel.addColumn("Address");
        traceTableModel.addColumn("Role");

        messagesTable.setOpaque(false);
        messagesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        messageScrollPane.setViewportView(messagesTable);
        messagesTable.setModel(messagesTableModel);

        traceTable.setOpaque(false);
        traceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        traceScrollPane.setViewportView(traceTable);
        traceTable.setModel(traceTableModel);

        JPanel tracePanel = new JPanel();
        tracePanel.setLayout(new BorderLayout());
        tracePanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 5, 30));
        JPanel messagesPanel = new JPanel(new GridLayout(2,1));
        messagesPanel.add(messageScrollPane);
        messagesPanel.add(traceScrollPane);
        tracePanel.add(messagesPanel, BorderLayout.CENTER);
        tracePanel.add(traceCommand, BorderLayout.SOUTH);

        brokersTableModel.addColumn("ID");
        brokersTableModel.addColumn("Address");
        brokersTableModel.addColumn("Role");
        brokerUnitsTableModel.addColumn("Super Units");
        brokerUnitsTableModel.addColumn("Peer Units");
        brokerUnitsTableModel.addColumn("Sub Units");

        brokersTable.setOpaque(false);
        brokersTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        mapScrollPane.setViewportView(brokersTable);
        brokersTable.setModel(brokersTableModel);

        brokerUnitsTable.setOpaque(false);
        brokerUnitsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        unitsScrollPane.setViewportView(brokerUnitsTable);
        brokerUnitsTable.setModel(brokerUnitsTableModel);

        JPanel mapPanel = new JPanel();
        mapPanel.setLayout(new BorderLayout());
        mapPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 5, 30));
        JPanel brokersPanel = new JPanel(new GridLayout(2,1));
        brokersPanel.add(mapScrollPane);
        brokersPanel.add(unitsScrollPane);
        mapPanel.add(brokersPanel, BorderLayout.CENTER);
        mapPanel.add(mapCommand, BorderLayout.SOUTH);

        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Insert Broker", insertPanel);
        tabbedPane.addTab("Remove Broker", removePanel);
        tabbedPane.addTab("Change Topology", changePanel);
        tabbedPane.addTab("Message Traces", tracePanel);
        tabbedPane.addTab("Network Map", mapPanel);

        informationBar.setHorizontalAlignment(SwingConstants.CENTER);

        JPanel backPanel = new JPanel(new BorderLayout());
        backPanel.add(adminAddressPanel, BorderLayout.NORTH);
        backPanel.add(tabbedPane, BorderLayout.CENTER);
        backPanel.add(informationBar, BorderLayout.SOUTH);
        this.setContentPane(backPanel);

        this.setSize(500, 500);
        this.setResizable(false);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width - 400) / 2, (screenSize.height - 500) / 2, 500, 500);

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setTitle("Admin Service Client");

        insertCommand.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                insertActionPerformed(event);
            }
        });
        removeCommand.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                removeActionPerformed(event);
            }
        });
        changeCommand.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                changeActionPerformed(event);
            }
        });
        traceCommand.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                traceActionPerformed(event);
            }
        });
        mapCommand.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent event)
            {
                mapActionPerformed(event);
            }
        });
        messagesTable.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent event)
            {
                updateMessageTrace(event);
            }
        });
        brokersTable.addMouseListener(new MouseAdapter()
        {
            public void mouseClicked(MouseEvent event)
            {
                updateBrokerUnits(event);
            }
        });
    }

    private void insertActionPerformed(ActionEvent event) {
        refresh();

        String adminAddressText = adminAddress.getText();
        if (adminAddressText == null || adminAddressText.isEmpty())
        {
            showError("Please set the address of the admin service");
        }

        String brokerEPR = insertBrokerAddress.getText();
        if (brokerEPR == null || brokerEPR.isEmpty())
        {
            showError("Please set the address of the broker service");
        }
        client.insertBroker(adminAddressText, brokerEPR);
    }

    private void removeActionPerformed(ActionEvent event) {
        refresh();

        String adminAddressText = adminAddress.getText();
        if (adminAddressText == null || adminAddressText.isEmpty())
        {
            showError("Please set the address of the admin service");
        }

        String brokerEPR = removeBrokerAddress.getText();
        if (brokerEPR == null || brokerEPR.isEmpty())
        {
            showError("Please set the address of the broker service");
        }
        client.removeBroker(adminAddressText, brokerEPR);
    }

    private void changeActionPerformed(ActionEvent event) {
        refresh();

        String adminAddressText = adminAddress.getText();
        if (adminAddressText == null || adminAddressText.isEmpty())
        {
            showError("Please set the address of the admin service");
        }

        String topology = topologies.getSelectedItem().toString();

        client.changeTopology(adminAddressText, topology);
    }

    private void traceActionPerformed(ActionEvent event) {
        refresh();

        String adminAddressText = adminAddress.getText();
        if (adminAddressText == null || adminAddressText.isEmpty())
        {
            showError("Please set the address of the admin service");
        }

        client.getMessageTrace(adminAddressText);
    }

    private void mapActionPerformed(ActionEvent event) {
        refresh();

        String adminAddressText = adminAddress.getText();
        if (adminAddressText == null || adminAddressText.isEmpty())
        {
            showError("Please set the address of the admin service");
        }

        client.getNetworkMap(adminAddressText);
    }

    private void updateMessageTrace (MouseEvent event) {
        refresh();
    }

    private void updateBrokerUnits (MouseEvent event) {
        refresh();
    }

    public void showInfo(String info)
    {
        informationBar.setText(info);
        informationBar.setForeground(Color.BLUE);
        this.repaint();
    }

    public void showError(String info)
    {
        informationBar.setText(info);
        informationBar.setForeground(Color.RED);
        this.repaint();
    }

    private void refresh()
    {
        informationBar.setText("  ");
    }
}
